package it.softphone.cmc.server.entity;

import it.softphone.cmc.server.security.AbstractMultiTenantRealm;
import it.softphone.cmc.shared.entity.Account;
import it.softphone.cmc.shared.entity.Attributes;
import it.softphone.cmc.shared.entity.TenantUser;
import it.softphone.commons.json.shared.JSONTransient;
import it.softphone.commons.service.LogAware;

import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.OneToOne;
import javax.persistence.Transient;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.ShortBlob;

@Entity
public class AccountEntity implements Account,LogAware {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static String DEFAULT_TENANT = "";
	
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
	@JSONTransient private Key GUID;
	
	//@Id 
	private java.lang.String id;
	@JSONTransient private java.lang.String passwd;
	
	private boolean suspended = false;
	@JSONTransient @Lob private ShortBlob salt;
	private java.util.Date dateRegistered;
	
	@Embedded 
	@OneToOne(cascade=CascadeType.ALL)
	private AttributesEntity attributes = new AttributesEntity();
	
	/// NEED ONLY FOR TRANSIENT DECLARATION
	@Transient protected final List<String> UID = null;
	//@Transient private Attributes attributes = null;
	
	//@OneToOne(fetch=FetchType.EAGER,cascade=CascadeType.ALL,mappedBy="tenant")
	//TenantEntity theTenant;
	
	private String deviceId;
	@Transient TenantUser user;

	private String mail;
	private String phone;
	
    protected <T> void checkNotNull( T object, String message ) {
    	if( object == null ) throw new NullPointerException(message);
    }

    @Override
	public String toString() {
		return String
				.format("AccountEntity [id=%s, passwd=%s, suspended=%s, salt=%s, dateRegistered=%s, attributes=%s, UID=%s, deviceId=%s, user=%s]",
						id, passwd, suspended, salt,
						dateRegistered, attributes, UID, deviceId, user);
	}


	@Override
	public String getId() {
		return id;
	}


	@Override
	public void setId(String value) {
		this.id = value;
	}


	public java.lang.String getPasswd() {
		return passwd;
	}

	public void setPasswd(String password) {
        checkNotNull(password, "User password can't be null");
        this.salt = new ShortBlob(AbstractMultiTenantRealm.salt().getBytes());
        this.passwd = AbstractMultiTenantRealm.hash(password, salt.getBytes());
    }

	public final Key getGUID() {
		return GUID;
	}

	public final void setGUID(Key value) {
		GUID = value;
	}


	@Override
	public void setUID(String value) {
		setGUID( KeyFactory.stringToKey(value) );
	}


	@Override
	public String getUID() {
		if( getGUID()==null) return null;
		return KeyFactory.keyToString(getGUID());
	}


	public Attributes getAttributes() {
		return attributes;
	}


	public void setAttributes(Attributes value) {
		attributes = (AttributesEntity)value;
		
	}

	@Override
	public final String getDeviceId() {
		return deviceId;
	}

	@Override
	public final void setDeviceId(String deviceId) {
		this.deviceId = deviceId;
	}


	@SuppressWarnings("unchecked")
	@Override
	public it.softphone.commons.json.server.JSONObject encodeAttributes() {	
		return  attributes.encodeAttributes();
	}

	@Override
	public void decodeAttributes(Object object) {
		attributes.decodeAttributes(object);
	}

	@Override
	public TenantUser getUser() {
		return user;
	}


	@Override
	public void setUser(TenantUser user) {
		this.user = user;
	}
	
	public boolean isSuspended() {
        return suspended;
    }

	public void setSuspended(boolean suspended) {
        this.suspended = suspended;
    }

	public Date getDateRegistered() {
        return dateRegistered == null ? null : new Date(dateRegistered.getTime());
    }

	public boolean isRegistered() {
        return getDateRegistered() != null;
    }

    public void register() {
        dateRegistered = new Date();
    }

	public byte[] getSalt() {
        return salt.getBytes();
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof AccountEntity) {
        	AccountEntity u = (AccountEntity)o;
            return getId().equals(u.getId())
                   && 
                   getPasswd().equals(u.getPasswd());
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return id.hashCode() * 31 + passwd.hashCode();
    }

	@Override
	public String getMail() {
		return mail;
	}

	@Override
	public void setMail(String mail) {
		this.mail = mail;
	}

	@Override
	public String getPhone() {
		return phone;
	}

	@Override
	public void setPhone(String number) {
		this.phone = number;
	}


}
